﻿ using System;
 using System.Runtime.InteropServices;
 
 namespace PBMApp.Tools
 {
     public class JustinIO
     {
         public class CommPort
         {

             public string PortNum ;
             public int BaudRate;
             public byte ByteSize;
             public byte Parity; // 0-4=no,odd,even,mark,space 
             public byte StopBits; // 0,1,2 = 1, 1.5, 2 
             public int ReadTimeout;
             public string CenterNumber; 
   
             //comm port win32 file handle
             private int hComm = -1;
   
             public bool Opened = false;
    
             //win32 api constants
             private const uint GENERIC_READ = 0x80000000;
             private const uint GENERIC_WRITE = 0x40000000;
             private const int OPEN_EXISTING = 3;  
             private const int INVALID_HANDLE_VALUE = -1;
   
             [StructLayout(LayoutKind.Sequential)]
                 public struct DCB 
             {
                 //taken from c struct in platform sdk 
                 public int DCBlength;           // sizeof(DCB) 
                 public int BaudRate;            // 指定当前波特率 current baud rate
                 // these are the c struct bit fields, bit twiddle flag to set
                 public int fBinary;          // 指定是否允许二进制模式,在windows95中必须主TRUE binary mode, no EOF check 
                 public int fParity;          // 指定是否允许奇偶校验 enable parity checking 
                 public int fOutxCtsFlow;      // 指定CTS是否用于检测发送控制，当为TRUE是CTS为OFF，发送将被挂起。 CTS output flow control 
                 public int fOutxDsrFlow;      // 指定CTS是否用于检测发送控制 DSR output flow control 
                 public int fDtrControl;       // DTR_CONTROL_DISABLE值将DTR置为OFF, DTR_CONTROL_ENABLE值将DTR置为ON, DTR_CONTROL_HANDSHAKE允许DTR"握手" DTR flow control type 
                 public int fDsrSensitivity;   // 当该值为TRUE时DSR为OFF时接收的字节被忽略 DSR sensitivity 
                 public int fTXContinueOnXoff; // 指定当接收缓冲区已满,并且驱动程序已经发送出XoffChar字符时发送是否停止。TRUE时，在接收缓冲区接收到缓冲区已满的字节XoffLim且驱动程序已经发送出XoffChar字符中止接收字节之后，发送继续进行。　FALSE时，在接收缓冲区接收到代表缓冲区已空的字节XonChar且驱动程序已经发送出恢复发送的XonChar之后，发送继续进行。XOFF continues Tx 
                 public int fOutX;          // TRUE时，接收到XoffChar之后便停止发送接收到XonChar之后将重新开始 XON/XOFF out flow control 
                 public int fInX;           // TRUE时，接收缓冲区接收到代表缓冲区满的XoffLim之后，XoffChar发送出去接收缓冲区接收到代表缓冲区空的XonLim之后，XonChar发送出去 XON/XOFF in flow control 
                 public int fErrorChar;     // 该值为TRUE且fParity为TRUE时，用ErrorChar 成员指定的字符代替奇偶校验错误的接收字符 enable error replacement 
                 public int fNull;          // eTRUE时，接收时去掉空（0值）字节 enable null stripping 
                 public int fRtsControl;     // RTS flow control 
                 /*RTS_CONTROL_DISABLE时,RTS置为OFF
         　        RTS_CONTROL_ENABLE时, RTS置为ON
      　　          RTS_CONTROL_HANDSHAKE时,
      　　          当接收缓冲区小于半满时RTS为ON
      　   　        当接收缓冲区超过四分之三满时RTS为OFF
      　　          RTS_CONTROL_TOGGLE时,
      　　          当接收缓冲区仍有剩余字节时RTS为ON ,否则缺省为OFF*/
 
                 public int fAbortOnError;   // TRUE时,有错误发生时中止读和写操作 abort on error 
                 public int fDummy2;        // 未使用 reserved 
    
                 public uint flags;
                 public ushort wReserved;          // 未使用,必须为0 not currently used 
                 public ushort XonLim;             // 指定在XON字符发送这前接收缓冲区中可允许的最小字节数 transmit XON threshold 
                 public ushort XoffLim;            // 指定在XOFF字符发送这前接收缓冲区中可允许的最小字节数 transmit XOFF threshold 
                 public byte ByteSize;           // 指定端口当前使用的数据位 number of bits/byte, 4-8 
                 public byte Parity;             // 指定端口当前使用的奇偶校验方法,可能为:EVENPARITY,MARKPARITY,NOPARITY,ODDPARITY  0-4=no,odd,even,mark,space 
                 public byte StopBits;           // 指定端口当前使用的停止位数,可能为:ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS  0,1,2 = 1, 1.5, 2 
                 public char XonChar;            // 指定用于发送和接收字符XON的值 Tx and Rx XON character 
                 public char XoffChar;           // 指定用于发送和接收字符XOFF值 Tx and Rx XOFF character 
                 public char ErrorChar;          // 本字符用来代替接收到的奇偶校验发生错误时的值 error replacement character 
                 public char EofChar;            // 当没有使用二进制模式时,本字符可用来指示数据的结束 end of input character 
                 public char EvtChar;            // 当接收到此字符时,会产生一个事件 received event character 
                 public ushort wReserved1;         // 未使用 reserved; do not use 
             }
 
             [StructLayout(LayoutKind.Sequential)]
                 private struct COMMTIMEOUTS 
             {  
                 public int ReadIntervalTimeout; 
                 public int ReadTotalTimeoutMultiplier; 
                 public int ReadTotalTimeoutConstant; 
                 public int WriteTotalTimeoutMultiplier; 
                 public int WriteTotalTimeoutConstant; 
             }  
 
             [StructLayout(LayoutKind.Sequential)] 
                 private struct OVERLAPPED 
             { 
                 public int  Internal; 
                 public int  InternalHigh; 
                 public int  Offset; 
                 public int  OffsetHigh; 
                 public int hEvent; 
             }  
   
             [DllImport("kernel32.dll")]
             private static extern int CreateFile(
                 string lpFileName,                         // 要打开的串口名称
                 uint dwDesiredAccess,                      // 指定串口的访问方式，一般设置为可读可写方式
                 int dwShareMode,                          // 指定串口的共享模式，串口不能共享，所以设置为0
                 int lpSecurityAttributes, // 设置串口的安全属性，WIN9X下不支持，应设为NULL
                 int dwCreationDisposition,                // 对于串口通信，创建方式只能为OPEN_EXISTING
                 int dwFlagsAndAttributes,                 // 指定串口属性与标志，设置为FILE_FLAG_OVERLAPPED(重叠I/O操作)，指定串口以异步方式通信
                 int hTemplateFile                        // 对于串口通信必须设置为NULL
                 );
             [DllImport("kernel32.dll")]
             private static extern bool GetCommState(
                 int hFile,  //通信设备句柄
                 ref DCB lpDCB    // 设备控制块DCB
                 ); 
             [DllImport("kernel32.dll")]
             private static extern bool BuildCommDCB(
                 string lpDef,  // 设备控制字符串
                 ref DCB lpDCB     // 设备控制块
                 );
             [DllImport("kernel32.dll")]
             private static extern bool SetCommState(
                 int hFile,  // 通信设备句柄
                 ref DCB lpDCB    // 设备控制块
                 );
             [DllImport("kernel32.dll")]
             private static extern bool GetCommTimeouts(
                 int hFile,                  // 通信设备句柄 handle to comm device
                 ref COMMTIMEOUTS lpCommTimeouts  // 超时时间 time-out values
                 ); 
             [DllImport("kernel32.dll")] 
             private static extern bool SetCommTimeouts(
                 int hFile,                  // 通信设备句柄 handle to comm device
                 ref COMMTIMEOUTS lpCommTimeouts  // 超时时间 time-out values
                 );
             [DllImport("kernel32.dll")]
             private static extern bool ReadFile(
                 int hFile,                // 通信设备句柄 handle to file
                 byte[] lpBuffer,             // 数据缓冲区 data buffer
                 int nNumberOfBytesToRead,  // 多少字节等待读取 number of bytes to read
                 ref int lpNumberOfBytesRead, // 读取多少字节 number of bytes read
                 ref OVERLAPPED lpOverlapped    // 溢出缓冲区 overlapped buffer
                 );
             [DllImport("kernel32.dll")] 
             private static extern bool WriteFile(
                 int hFile,                    // 通信设备句柄 handle to file
                 byte[] lpBuffer,                // 数据缓冲区 data buffer
                 int nNumberOfBytesToWrite,     // 多少字节等待写入 number of bytes to write
                 ref int lpNumberOfBytesWritten,  // 已经写入多少字节 number of bytes written
                 ref OVERLAPPED lpOverlapped        // 溢出缓冲区 overlapped buffer
                 );
             [DllImport("kernel32.dll")]
             private static extern bool CloseHandle(
                 int hObject   // handle to object
                 );
             [DllImport("kernel32.dll")]
             private static extern uint GetLastError();
   
             public void Open()
             {
   
                 DCB dcbCommPort = new DCB();
                 COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS(); 
      
                 // 打开串口 OPEN THE COMM PORT.
                 hComm = CreateFile(PortNum ,GENERIC_READ | GENERIC_WRITE,0, 0,OPEN_EXISTING,0,0);
                 // 如果串口没有打开，就打开 IF THE PORT CANNOT BE OPENED, BAIL OUT.
                 if(hComm == INVALID_HANDLE_VALUE) 
                 {
                     throw(new ApplicationException("非法操作，不能打开串口！"));
                 }
   
                 // 设置通信超时时间 SET THE COMM TIMEOUTS.
                 GetCommTimeouts(hComm,ref ctoCommPort);
                 ctoCommPort.ReadTotalTimeoutConstant = ReadTimeout;
                 ctoCommPort.ReadTotalTimeoutMultiplier = 0;
                 ctoCommPort.WriteTotalTimeoutMultiplier = 0;
                 ctoCommPort.WriteTotalTimeoutConstant = 0;  
                 SetCommTimeouts(hComm,ref ctoCommPort);
   
                 // 设置串口 SET BAUD RATE, PARITY, WORD SIZE, AND STOP BITS.
                 GetCommState(hComm, ref dcbCommPort);
                 dcbCommPort.BaudRate=BaudRate;
                 dcbCommPort.flags=0;
                 //dcb.fBinary=1;
                 dcbCommPort.flags|=1;
                 if (Parity>0)
                 {
                     //dcb.fParity=1
                     dcbCommPort.flags|=2;
                 }
                 dcbCommPort.Parity=Parity;
                 dcbCommPort.ByteSize=ByteSize;
                 dcbCommPort.StopBits=StopBits;
                 //if (!BuildCommDCB("9600,n,8,1  ", ref  dcbCommPort))
                 //{
                 //    throw (new ApplicationException("非法操作，不能打开串口！  "));
                 //}  
 
                 if (!SetCommState(hComm, ref dcbCommPort))
                 {
                     //uint ErrorNum=GetLastError();
                     throw(new ApplicationException("非法操作，不能打开串口！"));
                 }
                 //unremark to see if setting took correctly
                 //DCB dcbCommPort2 = new DCB();
                 //GetCommState(hComm, ref dcbCommPort2);
                 Opened = true;
             }
   
             public void Close() 
             {
                 if (hComm!=INVALID_HANDLE_VALUE) 
                 {
                     CloseHandle(hComm);
                 }
             }
   
             public byte[] Read(int NumBytes) 
             {
                 byte[] BufBytes;
                 byte[] OutBytes;
                 BufBytes = new byte[NumBytes];
                 if (hComm!=INVALID_HANDLE_VALUE) 
                 {
                     OVERLAPPED ovlCommPort = new OVERLAPPED();
                     int BytesRead=0;
                     ReadFile(hComm,BufBytes,NumBytes,ref BytesRead,ref ovlCommPort);
                     OutBytes = new byte[BytesRead];
                     Array.Copy(BufBytes,OutBytes,BytesRead);
                 } 
                 else 
                 {
                     throw(new ApplicationException("串口未打开！"));
                 }
                 return OutBytes;
             }
   
             public void Write(byte[] WriteBytes) 
             {
                 if (hComm!=INVALID_HANDLE_VALUE) 
                 {
                     OVERLAPPED ovlCommPort = new OVERLAPPED();
                     int BytesWritten = 0;
                     WriteFile(hComm,WriteBytes,WriteBytes.Length,ref BytesWritten,ref ovlCommPort);
                 }
                 else 
                 {
                     throw(new ApplicationException("串口未打开！"));
                 }  
             }
         }
 
         public class HexCon 
         {
             // 把十六进制字符串转换成字节型和把字节型转换成十六进制字符串 converter hex string to byte and byte to hex string
             public static string ByteToString(byte[] InBytes) 
             {
                 string StringOut="";
                 foreach (byte InByte in InBytes) 
                 {
                     StringOut=StringOut + String.Format("{0:X2} ",InByte);
                 }
                 return StringOut; 
             }
             public static byte[] StringToByte(string InString) 
             {
                 string[] ByteStrings;
                 ByteStrings = InString.Split(" ".ToCharArray());
                 byte[] ByteOut;
                 ByteOut = new byte[ByteStrings.Length-1];
                 for (int i = 0;i==ByteStrings.Length-1;i++) 
                 {
                     ByteOut[i] = Convert.ToByte(("0x" + ByteStrings[i]));
                 } 
                 return ByteOut;
             }
         }
     } 
 }